package cn.ant.service.impl;

import cn.ant.annotation.AopTimerLog;
import cn.ant.entity.FlowRollbackParams;
import cn.ant.entity.FlowStartParams;
import cn.ant.service.FlowManagerService;
import cn.ant.service.FlowTransactionalService;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.job.api.Job;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;


@Service
@Slf4j
public class FlowManagerServiceImpl implements FlowManagerService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private FlowTransactionalService flowTransactionalService;

    @Autowired
    private ManagementService managementService;



    /**
     * 部署流程
     *
     * @param flowFileName
     * @return
     */
    @Override
    public String deployFlow(String flowFileName) {
        log.info("deployFlow.start  {}", flowFileName);
        DeploymentBuilder deploymentBuilder = repositoryService
                .createDeployment()
                .name(flowFileName)
                .addClasspathResource("process/" + flowFileName + ".bpmn20.xml");
        Deployment deploy = deploymentBuilder.deploy();
        log.info("deployFlow.end {}", deploy);
        //返回部署的流程部署Id
        return deploy.getId();
    }

    /**
     * 启动流程
     *
     * @param flowStartParams
     * @return
     */
    @Override
    public String startFlow(FlowStartParams flowStartParams) {
        log.info("startFlow.start {}", flowStartParams);
       flowStartParams.getData().put("startFlow time is {}",new Date().toLocaleString());
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowStartParams.getFlowDefinitionId(), flowStartParams.getData());
        log.info("startFlow.end {}", processInstance);
        //返回流程实例Id
        return processInstance.getId();
    }

    @Override
    public String completeTaskByTaskId(String taskId) {
        log.info("completeTaskByTaskId.start {}", taskId);
        taskService.complete(taskId);
        log.info("completeTaskByTaskId.end");
        return null;
    }

    @Override
    public void rollBackSingle(FlowRollbackParams flowRollbackParams) {
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(flowRollbackParams.getFlowInstanceId())
                .moveActivityIdTo(flowRollbackParams.getFlowCurrentTaskDefinitionId(), flowRollbackParams.getFlowRollbackTaskDefinitionId())
                .changeState();
    }

//    @AopTimerLog
    @Override
    public List<Task> getRunningTaskList() {
        log.info("getRunningTaskList.start");
        List<Task> taskList = taskService.createTaskQuery().list();
        log.info("getRunningTaskList.finish {}", taskList);
        return taskList;
    }

    @Override
    public void batchTaskByFlowId(List<String> processIds) {
        //创建一个单线程池
//        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
        log.info("batchTaskByFlowId.start {}", processIds);
        List<Task> taskList = taskService.createTaskQuery().processInstanceIdIn(processIds).active().list();
        log.info("active list is {}", JSONUtil.parse(taskList));
        taskList.stream().forEach((task) -> {
            log.info("complete taskId is {}", task.getId());

            CompletableFuture.runAsync(() -> {
                flowTransactionalService.completeTask(task.getId());
            }).exceptionally((e) -> {
                e.printStackTrace();
                return null;
            });
        });
        log.info("batchTaskByFlowId.finish {}", taskList);
    }

    @Override
    public void batchJobByFlowId(List<String> processIds) {
        log.info("batchJobByFlowId.start");
        for (String processId : processIds) {
            List<Job> list = managementService.createJobQuery().processInstanceId(processId).list();
            log.info("batchJobByFlowId.list {}",list);
            for (Job job : list) {
                CompletableFuture.runAsync(()->{
                    managementService.executeJob(job.getId());
                }).exceptionally((e)->{
                    e.printStackTrace();
                    return null;
                });
            }
        }
        log.info("batchJobByFlowId.finish");
    }


    @Override
    public boolean isFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished()
                .processInstanceId(processInstanceId).count() > 0;
    }


    public byte[] getFlowImage(String processInstanceId) throws Exception {
        /**
         * 获得当前活动的节点
         */
        String processDefinitionId = "";
        if (this.isFinished(processInstanceId)) {// 如果流程已经结束，则得到结束节点
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId=pi.getProcessDefinitionId();
            log.info("createHistoricProcessInstanceQuery key {}",processDefinitionId);
        } else {// 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId=pi.getProcessDefinitionId();
            log.info("createProcessInstanceQuery key {}",processDefinitionId);
        }
        List<String> highLightedActivitis = new ArrayList<String>();

        /**
         * 获得活动的节点
         */
        List<HistoricActivityInstance> highLightedActivitList =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();

        for(HistoricActivityInstance tempActivity : highLightedActivitList){
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivitis, flows, engconf.getActivityFontName(),
                engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);
        byte[] buf = null;
        try {
            buf=IoUtil.readInputStream(in,"flow image name");
        } catch (Exception e) {
            log.error("操作异常",e);
        } finally {
            IoUtil.closeSilently(in);
        }
        return buf;

    }



}
